package mylittleinvestigations;

import org.newdawn.slick.GameContainer;
import org.newdawn.slick.geom.*;

public class MouseHelper
{
    private static final int ClickTimeThresholdMs = 250;
    private static final int ClickDistanceThresholdPx = 5;
 
    private static boolean clickPossible;
    private static boolean clicked;
    private static boolean previousWasLeftButtonDown;
    private static Vector2 previousMousePosition;
    //private static Cursor cursorToUpdateTo;
    
    private static long initialLeftButtonDownTime;
    private static Vector2 initialLeftButtonDownPosition;
    
    private static final Object mouseUpdateSyncObject = new Object();
    
    public static void Initialize()
    {
        MouseHelper.clicked = false;
        MouseHelper.previousWasLeftButtonDown = false;
        MouseHelper.previousMousePosition = new Vector2();
    }
    
    public static void Update(boolean isLeftButtonDown, int mouseX, int mouseY)
    {
        boolean currentWasLeftButtonDown = isLeftButtonDown;

        synchronized (mouseUpdateSyncObject)
        {
            if (clickPossible)
            {
                // We should only mark this as a click if it the up
                // comes in fast enough following the down, and if the
                // cursor didn't move very far.
                clickPossible =
                        System.currentTimeMillis() - initialLeftButtonDownTime <= ClickTimeThresholdMs &&
                        new Vector2(mouseX, mouseY).subtract(initialLeftButtonDownPosition).length() <= ClickDistanceThresholdPx;
            }
            
            if (!currentWasLeftButtonDown && previousWasLeftButtonDown)
            {
                // If a click is still possible now that the button has gone up,
                // we have a click.
                clicked = clickPossible;
            }
            else if (currentWasLeftButtonDown && !previousWasLeftButtonDown)
            {
                initialLeftButtonDownTime = System.currentTimeMillis();
                initialLeftButtonDownPosition = new Vector2(mouseX, mouseY);
                clickPossible = true;
            }

            previousWasLeftButtonDown = currentWasLeftButtonDown;

            previousMousePosition.setX(mouseX);
            previousMousePosition.setY(mouseY);
        }
    }
    
    public static void SetToArrowCursor()
    {
        //cursorToUpdateTo = Cursor.
    }

    public static void SetToHandCursor()
    {
        //cursorToUpdateTo = Cursors.Hand;
    }

    public static void ApplyCursorUpdate()
    {
        /*if (cursorToUpdateTo != Cursor.Current)
        {
            windowForm.Cursor = cursorToUpdateTo;
        }*/
    }

    public static boolean MouseOverRect(Rectangle rectangle)
    {
        boolean mouseOverRect = false;
        
        synchronized (mouseUpdateSyncObject)
        {
            mouseOverRect =
                !clicked &&
                !previousWasLeftButtonDown &&
                IsMouseInRect(rectangle);
        }
        
        return mouseOverRect;
    }

    public static boolean MouseDownOnRect(Rectangle rectangle)
    {
        boolean mouseDownOnRect = false;
        
        synchronized (mouseUpdateSyncObject)
        {
            mouseDownOnRect =
                previousWasLeftButtonDown &&
                IsMouseInRect(rectangle);
        }
        
        return mouseDownOnRect;
    }

    public static boolean MouseOverPolygon(Polygon polygon)
    {
        boolean mouseOverRect = false;
        
        synchronized (mouseUpdateSyncObject)
        {
            mouseOverRect =
                !clicked &&
                !previousWasLeftButtonDown &&
                IsMouseInPolygon(polygon);
        }
        
        return mouseOverRect;
    }

    public static boolean MouseDownOnPolygon(Polygon polygon)
    {
        boolean mouseDownOnRect = false;
        
        synchronized (mouseUpdateSyncObject)
        {
            mouseDownOnRect =
                previousWasLeftButtonDown &&
                IsMouseInPolygon(polygon);
        }
        
        return mouseDownOnRect;
    }

    public static boolean PressedAndHeldAnywhere()
    {
        boolean mouseDownAnywhere = false;
        
        synchronized (mouseUpdateSyncObject)
        {
            mouseDownAnywhere =
                previousWasLeftButtonDown &&
                !clickPossible &&
                IsMouseInViewport();
        }
        
        return mouseDownAnywhere;
    }

    public static boolean ClickedOnRect(Rectangle rectangle)
    {
        boolean clickedOnRect = false;
        
        synchronized (mouseUpdateSyncObject)
        {
            clickedOnRect =
                clicked &&
                IsMouseInRect(rectangle);
        }
        
        return clickedOnRect;
    }

    public static boolean ClickedOnPolygon(Polygon polygon)
    {
        boolean clickedOnRect = false;
        
        synchronized (mouseUpdateSyncObject)
        {
            clickedOnRect =
                clicked &&
                IsMouseInPolygon(polygon);
        }
        
        return clickedOnRect;
    }

    public static boolean ClickedAnywhere()
    {
        boolean clickedAnywhere = false;
        
        synchronized (mouseUpdateSyncObject)
        {
            clickedAnywhere =
                clicked &&
                IsMouseInViewport();
        }
        
        return clickedAnywhere;
    }
    
    public static Vector2 GetMousePosition()
    {
        Vector2 mousePosition;
        
        synchronized (mouseUpdateSyncObject)
        {
            mousePosition = previousMousePosition.Clone();
        }
        
        return mousePosition;
    }

    public static void HandleClick()
    {
        synchronized (mouseUpdateSyncObject)
        {
            clicked = false;
        }
    }

    private static boolean IsMouseInRect(Rectangle rectangle)
    {
        return
            previousMousePosition.getX() >= rectangle.getX() &&
            previousMousePosition.getX() <= rectangle.getX() + rectangle.getWidth() &&
            previousMousePosition.getY() >= rectangle.getY() &&
            previousMousePosition.getY() <= rectangle.getY() + rectangle.getHeight();
    }

    private static boolean IsMouseInPolygon(Polygon polygon)
    {
        return polygon.contains((int)previousMousePosition.getX(), (int)previousMousePosition.getY());
    }

    private static boolean IsMouseInViewport()
    {
        return IsMouseInRect(new Rectangle(0, 0, (float)Settings.DisplayBounds.getX(), (float)Settings.DisplayBounds.getY()));
    }
}